#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
挂机系统经验值问题诊断脚本
排查累计4小时但经验值为0的问题
"""

import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from database.database_manager import DatabaseManager
from src.character.experience_system import ExperienceSystem
from src.idle.mysql_idle_manager import MySQLIdleManager
from datetime import datetime, timedelta
import time
import json

def print_section(title):
    print(f"\n{'='*50}")
    print(f" {title}")
    print(f"{'='*50}")

def diagnose_idle_exp_issue():
    """诊断挂机系统经验值问题"""
    print("开始诊断挂机系统经验值问题...")
    
    # 初始化数据库连接
    db_manager = DatabaseManager()
    exp_system = ExperienceSystem()
    idle_manager = MySQLIdleManager()
    
    try:
        # 1. 检查挂机记录数据
        print_section("1. 检查挂机记录数据")
        check_idle_records(db_manager)
        
        # 2. 检查经验计算逻辑
        print_section("2. 检查经验计算逻辑")
        check_exp_calculation_logic(exp_system, idle_manager)
        
        # 3. 检查时间累计机制
        print_section("3. 检查时间累计机制")
        check_time_accumulation(db_manager)
        
        # 4. 检查经验更新触发机制
        print_section("4. 检查经验更新触发机制")
        check_exp_update_trigger(db_manager, idle_manager)
        
        # 5. 检查数据同步
        print_section("5. 检查数据同步")
        check_data_sync(db_manager)
        
        # 6. 模拟挂机过程
        print_section("6. 模拟挂机过程")
        simulate_idle_process(db_manager, idle_manager, exp_system)
        
        # 7. 提供修复建议
        print_section("7. 修复建议")
        provide_fix_suggestions()
        
    except Exception as e:
        print(f"诊断过程中发生错误: {e}")
        import traceback
        traceback.print_exc()

def check_idle_records(db_manager):
    """检查挂机记录数据"""
    print("检查挂机记录数据...")
    
    # 查询最近的挂机记录
    query = """
    SELECT ir.*, c.name as character_name, c.level, c.exp,
           il.name as location_name, il.base_exp_rate
    FROM idle_records ir
    JOIN characters c ON ir.character_id = c.id
    JOIN idle_locations il ON ir.location_id = il.id
    ORDER BY ir.created_at DESC
    LIMIT 10
    """
    
    records = db_manager.execute_query(query)
    
    if not records:
        print("❌ 没有找到挂机记录")
        return
    
    print(f"找到 {len(records)} 条最近的挂机记录:")
    total_duration = 0
    total_exp = 0
    
    for record in records:
        duration_seconds = record['duration_seconds'] or 0
        duration_hours = duration_seconds / 3600
        total_duration += duration_hours
        total_exp += record['exp_gained'] or 0
        
        print(f"  角色: {record['character_name']} (Lv.{record['level']})")
        print(f"  地点: {record['location_name']} (倍率: {record['base_exp_rate']})")
        print(f"  时长: {duration_hours:.2f}小时")
        print(f"  获得经验: {record['exp_gained'] or 0}")
        print(f"  状态: {record['status']}")
        print(f"  时间: {record['start_time']} - {record['end_time']}")
        print("  ---")
    
    print(f"\n总计挂机时长: {total_duration:.2f}小时")
    print(f"总计获得经验: {total_exp}")
    
    if total_duration > 0 and total_exp == 0:
        print("⚠️  发现问题: 有挂机时长但经验为0")
    elif total_exp > 0 and total_duration > 0:
        print(f"✅ 经验获取正常，平均每小时: {total_exp/total_duration:.2f}")
    elif total_duration == 0 and total_exp > 0:
        print("⚠️  发现问题: 挂机时长为0但有经验获得")
    else:
        print("⚠️  发现问题: 挂机时长和经验都为0")

def check_exp_calculation_logic(exp_system, idle_manager):
    """检查经验计算逻辑"""
    print("检查经验计算逻辑...")
    
    # 测试不同等级的经验计算
    test_levels = [1, 5, 10, 20]
    test_duration = 3600  # 1小时
    
    for level in test_levels:
        try:
            # 测试经验系统的计算
            base_rate = exp_system.calculate_idle_exp_rate(level)
            print(f"等级 {level}: 基础经验速率 = {base_rate}/小时")
            
            # 测试不同地点的经验计算
            locations = [
                {'id': 1, 'name': '新手村', 'base_exp_rate': 1.0},
                {'id': 2, 'name': '森林边缘', 'base_exp_rate': 1.2},
                {'id': 3, 'name': '深林密境', 'base_exp_rate': 1.5}
            ]
            
            for loc in locations:
                # 模拟角色数据
                character_data = {
                    'id': 1,
                    'level': level,
                    'exp': 0,
                    'attack': 10 + level * 2,
                    'defense': 8 + level * 2,
                    'speed': 12 + level,
                    'class': 'warrior'
                }
                
                # 计算预期经验
                expected_exp = base_rate * loc['base_exp_rate']
                print(f"  {loc['name']}: 预期 {expected_exp:.1f} 经验/小时")
                
        except Exception as e:
            print(f"❌ 等级 {level} 经验计算出错: {e}")

def check_time_accumulation(db_manager):
    """检查时间累计机制"""
    print("检查时间累计机制...")
    
    # 检查挂机记录的时间计算
    query = """
    SELECT 
        character_id,
        start_time,
        end_time,
        duration_seconds,
        TIMESTAMPDIFF(SECOND, start_time, end_time) as calculated_duration
    FROM idle_records
    WHERE end_time IS NOT NULL
    ORDER BY created_at DESC
    LIMIT 5
    """
    
    records = db_manager.execute_query(query)
    
    if not records:
        print("❌ 没有找到已完成的挂机记录")
        return
    
    print("检查时间计算准确性:")
    for record in records:
        stored_duration = record['duration_seconds'] or 0
        calculated_duration = record['calculated_duration'] or 0
        
        print(f"  记录ID: {record['character_id']}")
        print(f"  存储时长: {stored_duration}秒 ({stored_duration/3600:.2f}小时)")
        print(f"  计算时长: {calculated_duration}秒 ({calculated_duration/3600:.2f}小时)")
        
        if stored_duration == 0 and calculated_duration == 0:
            print(f"  ⚠️  两个时长都为0，可能是活跃记录")
        elif abs(stored_duration - calculated_duration) > 5:  # 允许5秒误差
            print(f"  ⚠️  时间计算不一致，差异: {abs(stored_duration - calculated_duration)}秒")
        else:
            print(f"  ✅ 时间计算正确")
        print("  ---")

def check_exp_update_trigger(db_manager, idle_manager):
    """检查经验更新触发机制"""
    print("检查经验更新触发机制...")
    
    # 检查当前正在挂机的角色
    query = """
    SELECT c.id, c.name, c.level, c.exp, c.is_idle,
           ir.start_time, ir.location_id, il.name as location_name
    FROM characters c
    LEFT JOIN idle_records ir ON c.id = ir.character_id AND ir.status = 'active'
    LEFT JOIN idle_locations il ON ir.location_id = il.id
    WHERE c.is_idle = 1
    """
    
    active_characters = db_manager.execute_query(query)
    
    if not active_characters:
        print("当前没有正在挂机的角色")
        return
    
    print(f"找到 {len(active_characters)} 个正在挂机的角色:")
    
    for char in active_characters:
        print(f"  角色: {char['name']} (ID: {char['id']})")
        print(f"  等级: {char['level']}, 经验: {char['exp']}")
        print(f"  挂机地点: {char['location_name']}")
        
        if char['start_time']:
            start_time = char['start_time']
            current_time = datetime.now()
            if isinstance(start_time, str):
                start_time = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
            
            duration = (current_time - start_time).total_seconds()
            print(f"  已挂机: {duration/3600:.2f}小时")
            
            # 尝试手动触发经验更新
            try:
                print(f"  尝试手动更新经验...")
                # 这里需要调用挂机管理器的更新方法
                # 注意：这可能需要根据实际的API来调整
                
            except Exception as e:
                print(f"  ❌ 手动更新失败: {e}")
        
        print("  ---")

def check_data_sync(db_manager):
    """检查数据同步"""
    print("检查数据同步...")
    
    # 检查角色表和挂机记录的一致性
    query = """
    SELECT 
        c.id,
        c.name,
        c.is_idle,
        COUNT(ir.id) as active_records,
        MAX(ir.start_time) as latest_start
    FROM characters c
    LEFT JOIN idle_records ir ON c.id = ir.character_id AND ir.status = 'active'
    GROUP BY c.id, c.name, c.is_idle
    HAVING c.is_idle != (COUNT(ir.id) > 0)
    """
    
    inconsistent = db_manager.execute_query(query)
    
    if inconsistent:
        print(f"❌ 发现 {len(inconsistent)} 个数据不一致的角色:")
        for char in inconsistent:
            print(f"  角色: {char['name']} (ID: {char['id']})")
            print(f"  is_idle: {char['is_idle']}, 活跃记录数: {char['active_records']}")
    else:
        print("✅ 角色状态与挂机记录一致")
    
    # 检查经验值更新时间
    query = """
    SELECT c.id, c.name, c.exp, c.updated_at,
           MAX(ir.end_time) as last_idle_end
    FROM characters c
    LEFT JOIN idle_records ir ON c.id = ir.character_id AND ir.status = 'completed'
    GROUP BY c.id
    HAVING last_idle_end > c.updated_at
    """
    
    outdated_exp = db_manager.execute_query(query)
    
    if outdated_exp:
        print(f"⚠️  发现 {len(outdated_exp)} 个角色的经验可能未及时更新")
        for char in outdated_exp:
            print(f"  角色: {char['name']}, 最后挂机结束: {char['last_idle_end']}, 经验更新: {char['updated_at']}")

def simulate_idle_process(db_manager, idle_manager, exp_system):
    """模拟挂机过程"""
    print("模拟挂机过程...")
    
    # 获取一个测试角色
    query = "SELECT * FROM characters WHERE name LIKE '%测试%' LIMIT 1"
    test_chars = db_manager.execute_query(query)
    
    if not test_chars:
        print("没有找到测试角色，跳过模拟")
        return
    
    char = test_chars[0]
    print(f"使用角色: {char['name']} (ID: {char['id']}, Lv.{char['level']})")
    
    # 获取一个挂机地点
    locations = db_manager.execute_query("SELECT * FROM idle_locations LIMIT 1")
    if not locations:
        print("没有找到挂机地点")
        return
    
    location = locations[0]
    print(f"使用地点: {location['name']} (倍率: {location['base_exp_rate']})")
    
    # 计算预期经验
    base_rate = exp_system.calculate_idle_exp_rate(char['level'])
    expected_exp_per_hour = base_rate * float(location['base_exp_rate'])
    test_duration = 60  # 测试1分钟
    expected_exp = expected_exp_per_hour * (test_duration / 3600)
    
    print(f"预期1分钟获得经验: {expected_exp:.2f}")
    
    # 记录初始经验
    initial_exp = char['exp']
    print(f"初始经验: {initial_exp}")
    
    try:
        # 开始挂机（这里需要根据实际API调整）
        print("开始模拟挂机...")
        
        # 创建挂机记录
        start_time = datetime.now()
        insert_query = """
        INSERT INTO idle_records (character_id, location_id, start_time, status)
        VALUES (%s, %s, %s, 'active')
        """
        db_manager.execute_update(insert_query, (char['id'], location['id'], start_time))
        
        # 等待一段时间
        print(f"等待 {test_duration} 秒...")
        time.sleep(test_duration)
        
        # 结束挂机
        end_time = datetime.now()
        duration = (end_time - start_time).total_seconds()
        
        # 计算实际经验
        actual_exp = expected_exp_per_hour * (duration / 3600)
        
        # 更新挂机记录
        update_query = """
        UPDATE idle_records 
        SET end_time = %s, duration_seconds = %s, exp_gained = %s, status = 'completed'
        WHERE character_id = %s AND status = 'active'
        """
        db_manager.execute_update(update_query, (end_time, duration, actual_exp, char['id']))
        
        # 更新角色经验
        new_exp = initial_exp + actual_exp
        update_char_query = "UPDATE characters SET exp = %s WHERE id = %s"
        db_manager.execute_update(update_char_query, (new_exp, char['id']))
        
        print(f"实际挂机时长: {duration:.1f}秒")
        print(f"计算获得经验: {actual_exp:.2f}")
        print(f"更新后经验: {new_exp}")
        
        # 验证更新
        verify_query = "SELECT exp FROM characters WHERE id = %s"
        result = db_manager.execute_query(verify_query, (char['id'],))
        if result:
            final_exp = result[0]['exp']
            print(f"验证最终经验: {final_exp}")
            
            if abs(final_exp - new_exp) < 0.01:
                print("✅ 经验更新成功")
            else:
                print(f"❌ 经验更新失败，期望: {new_exp}, 实际: {final_exp}")
        
    except Exception as e:
        print(f"❌ 模拟挂机失败: {e}")
        import traceback
        traceback.print_exc()

def provide_fix_suggestions():
    """提供修复建议"""
    suggestions = [
        "1. 检查挂机管理器中的经验计算逻辑是否正确调用经验系统",
        "2. 确认挂机结束时是否正确触发经验更新",
        "3. 检查数据库事务是否正确提交",
        "4. 验证挂机地点的经验倍率是否正确应用",
        "5. 检查角色等级对经验计算的影响",
        "6. 确认挂机状态更新的时机和逻辑",
        "7. 检查前端页面的数据刷新机制",
        "8. 验证服务器端的定时任务是否正常运行"
    ]
    
    print("修复建议:")
    for suggestion in suggestions:
        print(f"  {suggestion}")
    
    print("\n下一步行动:")
    print("  1. 根据诊断结果修复发现的问题")
    print("  2. 重新测试挂机功能")
    print("  3. 验证经验值能正确累计")
    print("  4. 检查前端显示是否同步")

if __name__ == "__main__":
    diagnose_idle_exp_issue()